﻿<!DOCTYPE HTML>
<html lang="zh">
<head>
<title>脚本语言 | AutoHotkey v2</title>
<meta name="description" content="Learn details about the language such as comments, expressions, control flow statements, structure of a script, etc." />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link href="static/theme.css" rel="stylesheet" type="text/css" />
<script src="static/content.js" type="text/javascript"></script>
<script type="text/javascript">$(function(){0<=window.navigator.userAgent.toLowerCase().indexOf("ucbrowser")&&CaoNiMaDeUc()})</script>
</head>
<body>

<h1>脚本语言</h1>
<p>一个 AutoHotkey 脚本从根本上说是使用 AutoHotkey 独有的自定义语言编写的程序要遵循的指令集合. 这种语言与其他几种脚本语言有一些相似之处, 但也有其独特的优势和缺陷. 本文档描述了该语言, 并试图指出常见的缺陷.</p>
<p class="note">有关 AutoHotkey 所使用的各种概念的更一般的解释, 请参阅<a href="Concepts.htm">概念和约定</a>.</p>

<h2 id="Table_of_Contents">目录</h2>
<ul>
  <li><a href="#general-conventions">常规约定</a></li>
  <li><a href="#comments">注释</a></li>
  <li><a href="#expressions">表达式</a>
  <ul>
    <li><a href="#strings">字符串 / 文本</a></li>
    <li><a href="#variables">变量</a></li>
    <li><a href="#constants">常量</a></li>
    <li><a href="#operators">运算符</a></li>
    <li><a href="#function-calls">函数调用</a>
    <ul>
      <li><a href="#function-call-statements">函数调用语句</a></li>
      <li><a href="#optional-parameters">可选参数</a></li>
    </ul></li>
    <li><a href="#operators-for-objects">对象的运算符</a></li>
    <li><a href="#expression-statements">表达式语句</a></li>
  </ul></li>
  <li><a href="#control-flow">控制流语句</a>
  <ul>
    <li><a href="#control-flow-vs">控制流 vs. 其他语句</a></li>
    <li><a href="#loop-statement">循环 语句</a></li>
    <li><a href="#not-control-flow">非控制流</a></li>
  </ul></li>
  <li><a href="#structure-of-a-script">脚本的结构</a>
  <ul>
    <li><a href="#global-code">全局代码</a></li>
    <li><a href="#functions">函数</a></li>
    <li><a href="#-include">#导入</a></li>
  </ul></li>
  <li><a href="#misc">杂项</a>
  <ul>
    <li><a href="#dynamic-variables">动态变量</a>
    <ul>
      <li><a href="#pseudo-arrays">伪数组</a></li>
      <li><a href="#associative-pseudo-arrays">关联伪数组</a></li>
    </ul></li>
    <li><a href="#labels">标签</a></li>
  </ul></li>
</ul>
<!-- TODO:
Directives
Declarations
Class definitions
Methods?
-->

<h2 id="general-conventions">常规约定</h2>
<p><strong>名称:</strong> 变量和函数名称不区分大小写(例如, <code>CurrentDate</code> 等同于 <code>currentdate</code>). 有关详细信息(如最大长度和可用字符), 请参阅<a href="Concepts.htm#names">名称</a>.</p>
<p><strong>无类型变量:</strong> 变量没有明确定义的类型; 相反, 任何类型的值都可以存储在任何变量中(不包括内置变量). 数字可能会自动转换为字符串(文本), 反之亦然, 这取决于实际情况.</p>
<p><strong>声明是可选的:</strong> 除了在<a href="Functions.htm">函数页面</a>上注明的地方外, 变量不需要声明; 它们的存在仅仅是通过使用它们(每个变量都是从空/空白开始的).</p>
<p><strong>空格通常被忽略:</strong> 缩进(前导空格) 对于编写可读代码非常重要, 但是程序不需要, 通常会被忽略. <em>通常</em> 在行尾的, 表达式内的(引号之间的除外), 以及命令参数之前和之后的空格和制表符会被忽略. 然而, 在一些情况下, 空格是重要的, 包括:</p>
<ul>
  <li><a href="#function-calls">函数</a>和方法调用要求在函数/方法名称和 <code>(</code> 之间没有空格.</li>
  <li>执行连接时需要空格.</li>
  <li>两个运算符之间可能需要空格, 以消除歧义.</li>
  <li>单行<a href="#comments">注释</a>如果不在行首, 则需要前导空格.</li>
</ul>
<p><strong>换行符是有意义的:</strong> 换行符通常作为语句分隔符, 终止前一个函数或其他语句. (<em>语句</em> 只是语言中表示要执行某些操作的最小的独立元素.) 这个例外是行延续(请参见下文).</p>
<p><strong>行延续:</strong> 长行可以分成一些小行, 以提高可读性和可维护性. 这是通过预处理实现的, 所以不属于这种语言的一部分. 有三种方法:</p>
<ul>
  <li><a href="Scripts.htm#continuation-line">延续前缀</a>: 以<a href="Variables.htm#operators">表达式运算符</a>(++ 和 -- 除外) 开头的行与前一行合并. 无论该行是否实际包含表达式, 都会合并行.</li>
  <li><a href="Scripts.htm#continuation-expr">延续闭环</a>: 在大多数情况下, 括在 (), [] 或 {} 中的子表达式可以自动跨越多行.</li>
  <li><a href="Scripts.htm#continuation-section">延续片段</a>: 片段中的多行与片段上面那一行合并, 延续片段以 <code>(</code> 开始, 以 <code>)</code> 结束(两个符号必须出现在行的开头, 不计空格).</li>
</ul>

<h2 id="comments">注释</h2>
<p><em>注释</em> 是脚本中被程序忽略的那部分文本. 它们通常用于添加解释或禁用部分代码.</p>
<p>可以通过在行的开头使用分号来注释脚本. 例如:</p>
<pre><em>; 这一整行都是注释.</em></pre>
<p>也可以在行的末尾添加注释, 此时分号左侧必须至少有一个空格或 tab. 例如:</p>
<pre>运行 "Notepad"  <em>; 这是与函数调用在同一行上的注释.</em></pre>
<p>此外, 可以使用 <code><em>/*</em></code> 和 <code><em>*/</em></code> 符号注释掉整块代码, <em>但仅当它们出现在行首时才有效</em>(对于 <code><em>*/</em></code>, 可以在行的开头或结尾处), 不包括空白字符, 如下例所示:</p>
<pre><em>/*
信息框 "这行被注释(禁用) 掉了."
信息框 "常见的错误:" */ " 这不会结束注释."
信息框 "这行被注释掉了."
*/</em>
信息框 "这行没有被注释."
<em>/* 这也是有效注释, 但是这一行不能有其他代码. */</em>
</pre>
<p>由于脚本运行时会忽略注释, 所以它们不会影响脚本性能或占用内存.</p>

<h2 id="expressions">表达式</h2>
<p><em>表达式</em> 是一个或多个<a href="Concepts.htm#values">值</a>, <a href="Concepts.htm#variables">变量</a>, <a href="#operators">运算符</a>和<a href="#function-calls">函数调用</a>的组合. 例如, <code>10</code>, <code>1+1</code> 和 <code>MyVar</code> 都是有效的表达式. 通常, 表达式将一个或多个值作为输入, 执行一个或多个操作, 并生成一个值作为结果. 找出表达式值的过程被称为 <em>计算</em>. 例如, 表达式 <code>1+1</code> <em>计算</em> 出数字 2.</p>
<p>简单的表达式可以拼凑在一起形成更复杂的表达式. 例如, 如果 <code>Discount/100</code> 将折扣百分比转换为分数, <code>1 - Discount/100</code> 计算剩余金额的分数, 而 <code>Price * (1 - Discount/100)</code> 应用它来产生净价格.</p>
<p><em>值</em> 是<a href="Concepts.htm#numbers">数字</a>, <a href="Concepts.htm#objects">对象</a>或<a href="Concepts.htm#strings">字符串</a>. <em>原义</em> 值是在脚本中实际写入的值; 当您在查看代码时可以看到该值(文字).</p>

<h3 id="strings">字符串 / 文本</h3>
<p class="note">有关字符串的更一般的解释, 请参阅<a href="Concepts.htm#strings">字符串</a>.</p>
<p><em>字符串</em> 或 <em>字符组成的串</em>, 只是一个文本值. 在表达式中, 原义的文本必须用引号引起来, 以区分变量名称或其他表达式. 这通常被称为 <em>加引号的原义字符串</em>, 或者为 <em>加引号的字符串</em>. 例如, <code>"this is a quoted string"</code> 和 <code>'so is this'</code>.</p>
<p>要在原义字符串中包含 <em>真实的</em> 引号字符, 请使用<a href="misc/EscapeChar.htm#quote">转义序列</a> <code>`"</code> 或 <code>`'</code>, 或将字符括在相反类型的引号中. 例如: <code>'She said, "An apple a day."'</code>.</p>
<p>加引号的字符串能包含其他的<a href="misc/EscapeChar.htm">转义序列</a>, 如 <code>`t</code>(制表符), <code>`n</code>(换行) 和 <code>`r</code>(回车).</p>

<h3 id="variables">变量</h3>
<p class="note">有关变量的基本解释和常规细节, 请参阅<a href="Concepts.htm#variables">变量</a>.</p>
<p><em>变量</em> 可以简单地通过写变量的名称来用于表达式. 例如, <code>A_ScreenWidth/2</code>. 但是, 变量不能在加引号的字符串中使用. 作为替代, 变量和其他值可以通过名为 <a href="Variables.htm#concat"><em>连接</em></a> 的过程与文本组合起来. 有两种方法能用于 <em>连接</em> 表达式中的值:</p>
<ul>
  <li>隐式连接: <code>&quot;The value is &quot; MyVar</code></li>
  <li>显式连接: <code>&quot;The value is &quot; . MyVar</code></li>
</ul>
<p>隐式连接也被称为 <em>自动连接</em>. 在这两种情况下, 变量和点之前的空格都是必需的.</p>
<p><a href="commands/Format.htm">格式化字符串</a> 函数也可以用于此目的. 例如:</p>
<pre>信息框 格式化字符串("You are using AutoHotkey v{1} {2}-bit.", 内_主程序版本, 内_指针大小*8)
</pre>
<p>要为变量赋值, 请使用 <code>:=</code> <a href="Variables.htm#AssignOp">赋值运算符</a>, 如 <code>变量 :=  &quot;Some text&quot;</code>.</p>
<p>表达式中的 <em>百分号</em> 用于创建<a href="#dynamic-variables">动态变量引用</a>和<a href="Functions.htm#DynCall">动态函数调用</a>, 但这些很不常见.</p>

<h3 id="constants">常量关键字</h3>
<p>常量就是一个不可改变的值, 给定一个符号名称. AutoHotkey 目前有以下常量:</p>
<table class="info">
  <tr><th>名称</th><th>值</th><th>类型</th><th></th></tr>
  <tr><td><code>False</code></td><td><code>0</code></td><td><a href="Concepts.htm#numbers">整数</a></td><td><a href="Variables.htm#Boolean">布尔值</a> false, 有时表示 "off", "no", 等等.</td></tr>
  <tr><td><code>True</code></td><td><code>1</code></td><td><a href="Concepts.htm#numbers">整数</a></td><td><a href="Variables.htm#Boolean">布尔值</a> true, 有时表示 "on", "yes", 等等.</td></tr>
</table>
<p>与只读<a href="Variables.htm#BuiltIn">内置变量</a>不同, 些变量不能通过<a href="#dynamic-variables">动态引用</a>返回.</p>

<h3 id="operators">运算符</h3>
<p><em>运算符</em> 采用符号或符号组的形式(如 <code>+</code> 或 <code>:=</code>), 或者下列其中一个单词 <code>and</code>, <code>or</code>, <code>not</code>, <code>is</code>, <code>in</code> 或 <code>contains</code>. 它们将一个, 两个或三个值作为输入, 并返回一个值作为结果. 用作运算输入的值或子表达式称为 <em>运算元</em>.</p>
<ul>
  <li><em>一元</em> 运算符可以写在单个运算元的前面或后面, 这取决于运算符. 例如, <code>-x</code> 或 <code>not keyIsDown</code>.</li>
  <li><em>二元</em> 运算符写在两个运算元之间. 例如, <code>1+1</code> 或 <code>2 * 5</code>.</li>
  <li>AutoHotkey 只有一个 <em>三元</em> 运算符, 它采用如下的形式 <a href="Variables.htm#ternary"><code>condition ? valueIfTrue : valueIfFalse</code></a>.</li>
</ul>
<p>一些一元和二元运算符共享相同的符号, 在这种情况下, 运算符的含义取决于它是写在两个值之前, 之后还是之间. 例如, <code>x-y</code> 执行减法, 而 <code>-x</code> 反转 <code>x</code> 的符号(从负值产生正值, 反之亦然).</p>
<p>除非在<a href="Variables.htm#operators">运算符表</a>中另有规定, 否则优先级相等的运算符(如 乘号(<code>*</code>) 和除号(<code>/</code>)) 按从左到右的顺序计算. 相反, 诸如加(<code>+</code>) 之类的优先级较低的运算符在诸如乘(<code>*</code>) 之类的优先级较高运算符之后被计算. 例如, <code>3 + 2 * 2</code> 作为 <code>3 + (2 * 2)</code> 计算. 括号可以用来覆盖优先级, 如以下示例所示: <code>(3 + 2) * 2</code></p>

<h3 id="function-calls">函数调用</h3>
<p class="note">有关函数和相关术语的一般解释, 请参阅<a href="Concepts.htm#functions">函数</a>.</p>
<p><em>函数</em> 接受可变数量的输入, 去执行一些动作或计算, 然后 <a href="Concepts.htm#return-a-value"><em>返回</em>(返回)</a> 一个结果. 函数的输入被称为<a href="Concepts.htm#parameters">参数</a>(<em>parameters</em> 或 <em>arguments</em>). 一个函数被简单地通过写它的名字, 后跟着用括号括起来的参数来 <a href="Concepts.htm#call"><em>called</em>(调用)</a>. 例如, 如果 <kbd>Shift</kbd> 键被按下, 则 <code>获取按键状态(&quot;Shift&quot;)</code> 返回(计算为) 1, 否则返回 0.</p>
<p class="warning"><strong>注意:</strong> 函数名和左括号之间不能有任何空格.
</p>
<p>对于刚接触编程的人来说, 括号的要求起初可能看起来很神秘或冗长, 但它们允许将函数调用与其他操作结合起来. 例如, 只有当两个键被物理按下时, 表达式 <code>获取按键状态(&quot;Shift&quot;, &quot;P&quot;) and 获取按键状态(&quot;Ctrl&quot;, &quot;P&quot;)</code> 才会返回 1.</p>
<p>函数名与变量名是分开的. 例如, <code>四舍五入</code> 可以同时是变量名和函数名, 而 <code>四舍五入 := 1</code> 不会以任何方式影响 <code>四舍五入(n)</code>.</p>
<p>与普通<a href="Functions.htm#Global">全局变量</a>不同, 默认情况下函数可以在其他函数的内部调用. 但是, <a href="Functions.htm#nested">嵌套函数</a>(即, 在另一个函数中 <em>定义的</em> 任何函数) 只能在包含它们的函数内通过名称来访问.</p>

<h4 id="function-call-statements">函数调用语句</h4>
<p>如果不需要函数的返回值, 并且函数名写在行首(或者在其他允许<a href="Concepts.htm#statement">语句</a>的上下文中, 如下面的 <code>否则</code> 或 <a href="Hotkeys.htm">热键</a>), 则可以省略括号. 在这种情况下, 行的其余部分作为函数的参数列表. 例如:</p>
<pre>result := 信息框("This one requires parentheses.",, "OKCancel")
信息框 "This one doesn't. The result was " result "."</pre>
<p>在同一上下文中调用<a href="Concepts.htm#methods">方法</a>时, 也可以省略圆括号, 但仅当目标对象是变量或直接命名的属性时才可以省略圆括号, 如 <code>myVar.myMethod</code> 或 <code>myVar.myProp.myMethod</code>.</p>

<h4 id="optional-parameters">可选参数</h4>
<p>可选参数可以简单地留空, 但是分隔逗号仍然是必需的, 除非所有后续参数也被省略. 例如, <a href="commands/Run.htm">运行</a> 函数可接受一至四个参数. 下列各项均有效:</p>
<pre>
运行 "notepad.exe", "C:\"
运行 "notepad.exe",, "Min"
运行("notepad.exe", , , notepadPID)
</pre>

<h3 id="operators-for-objects">对象的运算符</h3>
<p>这里表达式中使用的其他符号不完全符合上面定义的任何类别, 或影响表达式其他部分的含义, 如下所述. 这些都以某种方式与 <em>对象</em> 有关. 对于每个构造所做的事情提供一个完整的解释, 需要引入更多的概念, 而这不属于本节的范围.</p>
<p><code>Alpha.Beta</code> 通常称为 <em>成员访问</em>. <em>Alpha</em> 是一个普通变量, 可以用函数调用或其他一些返回对象的子表达式替换. 当计算时, 对象发送一个请求 &quot;给我属性 <em>Beta</em> 的值&quot;, &quot;在属性 <em>Beta</em> 中存储这个值&quot; 或 &quot;调用名为 <em>Beta</em> 的方法&quot;. 换句话说, <em>Beta</em> 是一个对对象有意义的名字; 它不是一个局部或全局变量.</p>
<p><code>Alpha.Beta()</code> 是一个 <em>方法调用</em>, 如上所述. 括号可在特定情况下省略; 请参阅<a href="#function-call-statements">函数调用语句</a>.</p>
<p><code>Alpha.Beta[Param]</code> 是成员访问的一种特殊形式, 其中包括了请求中的附加参数. <em>Beta</em> 只是一个简单的名称, <em>Param</em> 是一个普通的变量或子表达式, 或者是由逗号分隔的子表达式列表(与函数的参数列表中相同). 允许<a href="Functions.htm#VariadicCall">可变参数调用</a>.</p>
<p><code>Alpha.%vBeta%</code>, <code>Alpha.%vBeta%[Param]</code> 和 <code>Alpha.%vBeta%()</code> 也是成员访问, 但 <em>vBeta</em> 是一个变量或子表达式. 这允许在脚本运行时确定属性或方法的名称. 以这种方式调用方法时需要括号.</p>
<p><code>Alpha[Index]</code> 访问 <code>Alpha</code> 的 <em>默认属性</em>, 将 <code>Index</code> 作为参数. 在这种情况下, <em>Alpha</em> 和 <em>Index</em> 都是变量, 几乎可以用任何子表达式替换. 此语法通常用于检索<a href="objects/Array.htm">数组</a>或 <a href="objects/Map.htm">映射</a> 中的元素.</p>
<p id="array-literal"><code>[A, B, C]</code> 创建一个初始内容为 A, B 和 C(本例中的所有变量) 的<a href="objects/Array.htm">数组</a>, 其中 A 是元素 1.</p>
<p id="object-literal"><code>{Prop1: Value1, Prop2: Value2}</code> 创建一个<a href="objects/Object.htm">对象</a>, 其中 <em>Prop1</em> 和 <em>Prop2</em> 为原义的属性名. 稍后可以使用上面描述的 <em>成员访问</em> 语法检索值. 要将属性名作为表达式进行计算, 请用百分号将其括起来. 例如: <code>{%NameVar%: ValueVar}</code>.</p></p>
<p><code>MyFunc(Params*)</code> 是一个<a href="Functions.htm#VariadicCall">可变函数调用</a>. 星号必须紧接在函数参数列表末尾的右括号之前. <em>Params</em> 必须是返回<a href="objects/Array.htm">数组</a>或其他可枚举对象的变量或子表达式. 虽然在任何地方使用 <code>Params*</code> 都是无效的, 但它可以用在数组标识符(<code>[A, B, C, ArrayToAppend*]</code>) 或属性参数列表(<code>Alpha.Beta[Params*]</code> 或 <code>Alpha[Params*]</code>) 中.</p>

<h3 id="expression-statements">表达式语句</h3>
<p>并不是所有的表达式都可以单独在一行上使用. 例如, 只包含 <code>21*2</code> 或 <code>&quot;Some text&quot;</code> 的行就没有任何意义. 表达式 <em>语句</em> 是一个单独使用的表达式, 通常利用它的附加作用. 大多数带有附加作用的表达式都可以这样使用, 所以一般不需要记住本节的细节.</p>
<p>以下类型的表达式可以用作语句:</p>
<p>赋值(如 <code>x := y</code>), 复合赋值(如 <code>x += y</code>) 和增量/减量运算符(如 <code>++x</code> 和 <code>x--</code>).</p>
<p class="warning"><strong>已知限制:</strong> 对于 <code>x++</code> 和 <code>x--</code>, 目前变量名和运算符之间不能有空格.</p>
<p>函数调用(如 <code>MyFunc(Params)</code>). 但是, 一个独立的函数调用不能跟随一个左大括号 <code>{</code>(在行尾或下一行), 因为它会与函数声明混淆.</p>
<p>方法调用(如 <code>MyObj.MyMethod()</code>).</p>
<p>使用方括号的成员访问(如 <code>MyObj[Index]</code>), 它可能有类似于函数调用的附加作用.</p>
<p>三元表达式(如 <code>x? CallIfTrue() : CallIfFalse()</code>). 但是, 使用下面的规则更安全; 也就是说, 始终将表达式(或条件) 括在括号中.</p>
<p class="warning"><strong>已知限制:</strong>  由于<a href="#function-call-statements">函数调用语句</a>的模糊性, 以变量名和空格开头的条件(还包含其他操作符) 应该用圆括号括起来. 例如, <code>(x + 1) ? y : z</code> 和 <code>x+1 ? y : z </code> 是表达式语句, 但是 <code>x + 1 ? y : z</code> 是函数调用语句.</p>
<p class="warning"><strong>注意:</strong> 条件不能以 <code>!</code> 或任何其他表达式运算符开头, 因为它将被解释为<a href="Scripts.htm#continuation-line">延续行</a>.</p>
<p>以 <code>(</code> 开始的表达式. 但是, 通常必须在同一行有一个匹配的 <code>)</code>, 否则该行将被解释为<a href="Scripts.htm#continuation">延续片段</a>的开始.</p>
<p>以双百分号开始的表达式(如 <code>%varname% := 1</code>). 这主要是由于实现的复杂性.</p>
<p>为简单起见, 也允许以上面描述的任一表达式(但不包括下面描述的) 开始的表达式. 例如, <code>MyFunc()+1</code> 目前是允许的, 尽管 <code>+1</code> 没有效果, 其结果会被丢弃. 由于错误检查的增强, 这些表达式在将来可能会失效.</p>
<p><a href="#function-call-statements">函数调用语句</a>类似于表达式语句, 但在技术上不是纯表达式. 例如, <code>信息框 "Hello, world!"</code>, <code>myGui.显示</code> 或 <code>x.y.z "my parameter"</code>.</p>

<h2 id="control-flow">控制流语句</h2>
<p class="note">有关控制流的一般说明, 请参阅<a href="Concepts.htm#control-flow">控制流</a>.</p>
<p><a href="Concepts.htm#statement">语句</a> 通过将他们括在大括号(<code>{}</code>) 中(如 C, JavaScript 和类似语言) 组合成 <a href="commands/Block.htm"><em>块</em></a>, 但通常大括号必须出现在行的开头. 控制流语句可以应用于整个块或者只是单一语句.</p>
<p>控制流程语句的<a href="Concepts.htm#cf-body">主体</a>总是 <em>一组</em> 语句. 块被视为一组语句, 就像控制流语句及其主体一样. 以下相关语句与其主体一起彼此分组: <code>如果</code> 和 <code>否则</code>; <code>循环</code>/<code>遍历</code> 和 <code>直到</code>; <code>Try</code> 和 <code>捕获</code> 和/或 <code>收尾</code>. 换句话说, 当这些语句组作为一个整体使用时, 并不总是需要用大括号括起来(但是, 为了清楚起见, 一些编码样式总是包含大括号).</p>
<p>控制流语句, 它具有一个主体, 因此必须总是跟着一个相关的语句或一组语句: <code>如果</code>, <code>否则</code>, <code>循环</code>, <code>While</code>, <code>遍历</code>, <code>Try</code>, <code>捕获</code> 和 <code>收尾</code>.</p>
<p id="control-flow-list">下面的控制流语句如下::</p>
<ul>
  <li>一个<a href="commands/Block.htm">块</a>(用一对大括号表示) 将零个或多个语句组合为一个语句.</li>
  <li><a href="commands/If.htm">如果 语句</a>导致其主体被执行或不依赖条件. 其后可以跟一个 <a href="commands/Else.htm">否则</a> 语句, 只有当条件不满足时才执行.</li>
  <li><a href="commands/Goto.htm">跳转</a> 跳转到指定的标签并继续执行.</li>
 <li><a href="commands/Return.htm">返回</a> 从一个函数返回.</li>
  <li>一个 <a href="#loop-statement">循环(循环) 语句</a> (<a href="commands/Loop.htm">循环</a>, <a href="commands/While.htm">While</a> 或 <a href="commands/For.htm">遍历</a>) 重复执行其主体.
  <ul>
    <li><a href="commands/Break.htm">跳出</a> 退出(终止) 一个循环.</li>
    <li><a href="commands/Continue.htm">跳过</a> 跳过当前循环迭代的其余部分, 并开始一个新的循环.</li>
    <li><a href="commands/Until.htm">直到</a> 直到表达式计算结果为 true 时, 循环终止. 表达式在每次迭代之后被计算.</li>
  </ul></li>
  <li><a href="commands/Switch.htm">判断</a> 执行互斥候选项列表中的一个项目.</li>
  <li>异常处理:
  <ul>
    <li><a href="commands/Try.htm">Try</a> 保护它的主体不受运行错误和 报错 语句抛出的异常的影响.</li>
    <li><a href="commands/Catch.htm">捕获</a> 在 try 语句中抛出异常后执行它的主体(仅当在抛出异常的情况下).</li>
    <li><a href="commands/Finally.htm">收尾</a> 在当控制权从 try 或 捕获 语句的主体转出时, 执行其主体.</li>
    <li><a href="commands/Throw.htm">报错</a> 抛出一个异常, 通过 try/catch 或显示错误对话框来处理.</li>
  </ul></li>
</ul>

<h3 id="control-flow-vs">控制流与其他语句</h3>
<p>控制流语句与<a href="#function-call-statements">函数调用语句</a>在以下几个方面不同:</p>
<ul>
  <li><a href="commands/Block.htm">块</a>的左大括号可以写在 <a href="commands/If.htm">如果</a>, <a href="commands/Else.htm">否则</a>, <a href="#loop-statement">循环</a>, <a href="commands/While.htm">While</a>, <a href="commands/For.htm">遍历</a>, <a href="commands/Try.htm">Try</a>, <a href="commands/Catch.htm">捕获</a> 或 <a href="commands/Finally.htm">收尾</a> 语句(基本上是任何具有<a href="Concepts.htm#cf-body">主体</a>的控制流语句) 同一行的末尾. 这被称为 One True Brace(OTB) 样式.</li>
  <li><a href="commands/Else.htm">否则</a>, <a href="commands/Try.htm">Try</a> 和 <a href="commands/Finally.htm">收尾</a> 允许任何有效的语句在其右侧, 因为它们需要一个<a href="Concepts.htm#cf-body">主体</a>但没有参数.</li>
  <li><a href="commands/If.htm">如果</a>, <a href="commands/While.htm">While</a>, <a href="commands/Return.htm">返回</a>, <a href="commands/Until.htm">直到</a>, <a href="commands/Loop.htm">循环 <em>Count</em></a> 和 <a href="commands/Goto.htm">跳转</a> 允许在名称后立即使用左括号, 将整个参数列表括起来. 虽然这些看起来像函数调用, 但它们不是, 也不能在表达式中间使用. 例如, <code>如果(expression)</code>.</li>
  <li>不能通过定义具有相同名称的函数来覆盖控制流语句.</li>
</ul>

<h3 id="loop-statement">循环 语句</h3>
<p>有几种类型的 循环 语句:</p>
<ul>
  <li><a href="commands/Loop.htm">循环 <em>Count</em></a> 重复执行一个语句: 可以指定表示重复次数的数字(Count) 或直到遇到 <a href="commands/Break.htm">跳出</a>.</li>
  <li><a href="commands/LoopReg.htm">遍历注册表</a> 获取指定的注册表子键的内容,每次一个项目.</li>
  <li><a href="commands/LoopFiles.htm">遍历文件</a> 获取指定的文件或文件夹, 每次一个.</li>
  <li><a href="commands/LoopParse.htm">循环转换</a> 从一个字符串中获取子字符串(片段), 每次一个.</li>
  <li><a href="commands/LoopRead.htm">循环读取</a> 获取文本文件中的行, 每次一行.</li>
  <li><a href="commands/While.htm">While</a> 重复执行一个语句, 一直到指定的<a href="Variables.htm#Expressions">表达式</a>计算结果为假. 每次迭代(重复) 前计算表达式的结果.</li>
  <li><a href="commands/For.htm">遍历</a> 对每一个值或枚举器返回的每对键值对执行一个语句, 如对象中的每对键值对.</li>
</ul>
<p><a href="commands/Break.htm">跳出</a> 退出(终止) 一个循环, 有效地跳到循环主体后面的下一行.</p>
<p><a href="commands/Continue.htm">跳过</a> 跳过当前循环迭代的其余部分, 并开始一个新的循环.</p>
<p><a href="commands/Until.htm">直到</a> 表达式计算结果为 true 时, 循环终止. 表达式在每次迭代之后被重新计算.</p>
<p id="named-loops"><a href="#labels">标签</a>可以用来 &quot;命名&quot; <a href="commands/Continue.htm">跳过</a> 和 <a href="commands/Break.htm">跳出</a> 的循环. 这允许脚本轻松地继续或跳出任何数量的嵌套循环而不使用 <a href="commands/Goto.htm">跳转</a>.</p>
<p>内置变量 <strong>内_循环次数</strong> 包含当前循环迭代的编号. 它在第一次执行循环主体时为 1. 第二次时为 2; 依次类推. 如果一个内部循环被外部循环包围, 则内部循环优先. 内_循环次数 适用于所有类型的循环, 但在循环之外为 0.</p>
<p>对于某些循环类型, 其他内置变量返回有关当前循环项 (注册表键/值, 文件, 子字符串或文本行) 的信息. 这些变量的名称以 <strong>A_Loop</strong> 开头, 如 内_遍历文件名 和 内_循环读取行. 它们的值总是对应于最近开始的(但还没有停止) 循环的适应类型. 例如, 内_循环属性 返回最里层解析循环中的当前子字符串, 即使它在文件或注册表循环中使用.</p>
<pre>t := &quot;column 1`tcolumn 2`nvalue 1`tvalue 2&quot;
循环转换 t, "`n"
{
    rowtext := 内_循环属性
    rownum := 内_循环次数  <em>; 保存这个用于下面的第二个循环中.</em>
    循环转换 rowtext, "`t"
    {
        信息框 rownum ":" 内_循环次数 " = " 内_循环属性
    }
}
</pre>
<p>循环变量也可以在循环主体外部使用, 例如在循环中调用的函数中.</p>

<h3 id="not-control-flow">非控制流</h3>
<p>像指令, 标签, 双冒号热键和热字串标签, 和没有赋值的声明都会在脚本加载文件的时候被处理, 它们不受控制流的制约. 换句话说, 在脚本执行任何控制流程语句之前, 它们将无条件生效. 同样, <a href="commands/_HotIf.htm">#动态判断</a> 指令不能影响控制流; 它只是设置代码中指定的任何热键和热字串的条件. 每次按下时都会计算热键的条件, 而不是在代码中遇到 #动态判断 指令时.</p>

<h2 id="structure-of-a-script">脚本的结构</h2>

<h3 id="global-code">全局代码</h3>
<p>脚本加载完成后, <em>自动执行线程</em> 从脚本的顶行开始执行, 一直到被指示停止为止, 比如通过 <a href="commands/Return.htm">返回</a>, <a href="commands/ExitApp.htm">退出应用</a> 或 <a href="commands/Exit.htm">退出</a>. 脚本的物理结束也作为 <a href="commands/Exit.htm">退出</a>.</p>
<p>全局代码, 或全局<a href="Concepts.htm#scope">范围</a>内的代码, 是任何不在函数或类定义内的可执行代码. 那里的任何变量引用都被称为<a href="Functions.htm#Global">全局的</a>, 因为它们可以被任何函数(通过适当的声明) 访问. 这样的代码通常用于配置适用于每个新启动的<a href="misc/Threads.htm">线程</a>的设置, 或者<a href="Concepts.htm#uninitialised-variables">初始化</a>热键和其他函数使用的全局变量.</p>
<p>在启动时执行的代码(在脚本启动时立即执行) 通常被放在文件的顶部. 然而, 这样的代码也可以放在整个文件中, 在函数和类定义之间(但不是在里面). 这是因为每当在执行过程中遇到的每个函数或类定义的主体都会被跳过. 在某些情况下, 脚本的整个目的可能用全局代码来执行.</p>
<p><strong>相关:</strong> <a href="Scripts.htm#auto">脚本启动(自动执行线程)</a></p>

<h3 id="subroutines">子程序</h3>
<p><em>子程序</em>(也称为 <em>sub</em> 或 <em>procedure</em>) 是一个可重复使用的代码块, 可按需执行. 子程序是通过定义 <em>函数</em> 创建的(见下文). 这些术语通常可以在 AutoHotkey v2 中互换, 函数是子程序的唯一类型.</p>

<h3 id="functions">函数</h3>
<p><strong>相关:</strong> <a href="Functions.htm">函数</a>(有关函数定义)</p>
<p>除了调用许多有用的<a href="commands/index.htm">预置函数</a>外, 脚本还可以定义自己的函数. 这些函数一般有两种使用方式:</p>
<ol>
  <li>函数可以被脚本本身调用. 这种函数可能被用来避免重复, 使代码更容易管理, 或者可能用于其他目的.</li>
  <li>函数可以被程序调用, 以响应一些事件, 例如用户按下热键. 例如, 每个热键都与一个函数相关联, 每当热键被按下时就会执行.</li>
</ol>
<p>有多种方法可以定义一个函数:</p>
<ul>
  <li><a href="Functions.htm">函数定义</a>由名称, 括号和代码<a href="commands/Block.htm">块</a>组成. 这定义的函数, 可以通过带有名称的<a href="#function-calls">函数调用</a>或<a href="#function-call-statements">函数调用语句</a>来执行. 例如:
<pre>SayHello()  <em>; 定义 SayHello 函数.</em>
{
    信息框 "Hello!"
}

SayHello  <em>; 调用 SayHello 函数.</em></pre>
  </li>
  <li><a href="Hotkeys.htm">热键</a>或<a href="Hotstrings.htm">热字串</a>定义, 由热键或热字串和单条<a href="Concepts.htm#statement">语句</a>或代码<a href="commands/Block.htm">块</a> 组成. 这种类型的函数不能直接调用, 而是在热键或热串被激活时执行. 例如:
<pre>#w::运行 "wordpad"  <em>; 按 Win-W 运行 Wordpad.</em>
#n::  <em>; 按 Win-N 运行 Notepad.</em>
{
    运行 "notepad"
}</pre>
  </li>
  <li><a href="Variables.htm#fat-arrow">胖箭头表达式</a>定义了一个函数, 它计算<a href="#expressions">表达式</a>并<a href="Concepts.htm#return-a-value">返回</a>其结果, 而不是执行一个代码块. 这种函数通常没有名称, 因为它们是直接传递给另一个函数的. 例如:
    <pre>设置定时器 () => 信息框("Hello!"), -1000  <em>; 1 秒后说 hello.</em></pre></pre>
  </li>
  <li>胖箭头语法也可以在表达式之外使用, 作为普通函数或方法定义的简写. 例如, 下面相当于上面的 SayHello 定义, 只不过这个定义返回的是 "OK":
    <pre>SayHello() => 信息框("Hello!")</pre>
  </li>
</ul>
<p>函数中的变量默认为函数的<a href="Functions.htm#Local">局部变量</a>, 除非是在<a href="Functions.htm#nested">嵌套函数</a>中引用外部函数的局部变量, 或者是在全局范围内使用 <code>=&gt;</code> 时的任何变量(不是在类或其他函数中).</p>
<p>函数可以选择<a href="Concepts.htm#parameters">接受参数</a>. 参数是通过在括号内列出它们来定义的. 例如:</p>
<pre>MyFunction(FirstParameter, Second, ByRef Third, Fourth:=&quot;&quot;)
{
    <em>;...</em>
    返回 &quot;a value&quot;
}
</pre>
<p>和函数调用一样, 函数名和左括号之间不能有空格.</p>
<p>右括号和左大括号之间的换行符是可选的. 两者之间可以有任意数量的空格或注释.</p>
<p><a href="Functions.htm#ByRef">ByRef</a> 表示该参数接受变量引用, 使该参数成为调用者传递的变量的别名. 如果调用者没有传递一个变量, 那么这个参数就像一个普通的局部变量. ByRef 参数也可以是可选的.</p>
<p><a href="Functions.htm#optional">可选</a>参数通过在参数名称后面指定 <code>:=</code> 和一个默认值, 该值必须是加引号的原义字符串, 数字, <code>true</code>, <code>false</code> 或 <code>unset</code>.</p>
<p>函数可以<a href="Functions.htm#return">返回一个值</a>. 如果不是, 则默认返回一个空字符串.</p>
<p>函数定义不需要在调用该函数之前.</p>
<p class="note">有关详情, 请参阅<a href="Functions.htm">函数</a>.</p>

<h3 id="-include">#导入</h3>
<p><a href="commands/_Include.htm">#导入</a> 指令使脚本的行为就像指定文件的内容出现在这个确切位置一样. 这通常用于将代码组织到单独的文件中, 或者使用其他用户编写的脚本库.</p>
<p>#导入 文件可以包含在<a href="Scripts.htm#auto">脚本启动</a>时要执行的<a href="#global-code">全局代码</a>, 但是和主脚本文件中的代码一样, 只有当自动执行线程在 #导入 指令之前没有被终止(比如用一个无条件的 <code>返回</code>) 才会执行这些代码. 如果任何代码由于之前的 <code>返回</code> 而无法执行, 默认会显示一个<a href="commands/_Warn.htm#Unreachable">警告</a>.</p>
<p>与 C/C++ 不同, 如果以前的指令已包含该文件, #导入 不做任何事情. 要多次包含同一文件的内容, 请使用 <a href="commands/_Include.htm">#再次导入</a>.</p>
<p>如果包含函数的脚本文件被保存在一个标准的位置并进行适当的命名, 则它们可以 <em>自动包含</em>, 而不必使用 #导入. 其效果与在主脚本文件末尾使用 #导入 相似. 有关详情, 请参阅<a href="Functions.htm#lib">函数库</a>.</p>

<h2 id="misc">杂项</h2>

<h3 id="dynamic-variables">动态变量</h3>
<p><em>动态变量引用</em> 接受一个文本值, 并将其解释为变量的名称.</p>
<p>动态变量引用的最常见形式称为 <em>双重引用</em> 或 <em>双重解引</em>. 在执行双重引用之前, 目标变量的名称存储在第二个变量中. 然后可以通过使用双重引用将第二个变量间接地将值赋给目标变量. 例如:</p>
<pre>target := 42
second := &quot;target&quot;
信息框  second   <em>; 普通(单重) 变量引用 =&gt; target</em>
信息框 %second%  <em>; 双重解引 =&gt; 42</em>
</pre>
<p>目前, 第二种情况下, <code>second</code> 必须总是包含一个变量名; 任意表达式不被支持.</p>
<p>动态变量引用也可以采用一个或多个文本文本和一个或多个变量的内容, 并将它们组合在一起组成一个单一变量名. 在没有空格的情况下, 这只需简单地按顺序写入名称和百分号括起来的变量. 例如, <code>MyArray%内_循环次数%</code> 或 <code>MyGrid%X%_%Y%</code>. 这用于访问 <em>伪数组</em>, 如下所示.</p>
<p>这些技术也可以应用于对象的属性和方法. 例如:</p>
<pre>clr := {}
遍历 n, component in ["red", "green", "blue"]
    clr.%component% := 随机数(0, 255)
信息框 clr.red "," clr.green "," clr.blue</pre>

<h4 id="pseudo-arrays">伪数组</h4>
<p><em>伪数组</em> 实际上只是一堆分开的变量, 但是有一个命名模式, 可以像数组元素一样使用它. 例如:</p>
<pre>
MyArray1 := "A"
MyArray2 := "B"
MyArray3 := "C"
循环 3
    信息框 MyArray%内_循环次数%  <em>; 显示 A, 然后 B, 最后 C.</em>
</pre>
<p>由于单个元素只是普通变量, 所以可以赋值或获取一个值, 但不能 <em>删除</em> 或 <em>插入</em> 元素. 因为伪数组本身并不存在, 所以不能将它传递给函数或从函数返回, 或者作为一个整体进行复制. 由于这些原因, 通常建议在可能的情况下使用<a href="Objects.htm#Usage_Simple_Arrays">普通数组</a>.</p>

<h4 id="associative-pseudo-arrays">关联伪数组</h4>
<p>用于形成最终变量名称的 &quot;index(索引)&quot; 不一定是数字; 它可以是一个字母或关键字, 使伪数组类似于<a href="Objects.htm#Usage_Associative_Arrays">关联数组</a>或<a href="Objects.htm">对象</a>.</p>

<h3 id="labels">标签</h3>
<p>标签标识只是一行代码, 可以用作 <a href="commands/Goto.htm">跳转</a> 的目标, 或<a href="#named-loops">指定一个循环</a>来跳出或继续. 标签由一个名称后跟一个冒号组成:</p>
<pre>this_is_a_label:
</pre>
<p>除了空格和注释外, 其他代码不能和标签写在同一行. 有关详情, 请参阅<a href="misc/Labels.htm">标签</a>.</p>

</body>
</html>